//Define XBOX_GAME when compiling for the XBox 360 platform.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Microsoft.Win32;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace _1600hours
{

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        #region Command Console
#if DEBUG
        public string command;
        bool commandExists;
        List<Command> commands = new List<Command>();
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool AllocConsole();

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool FreeConsole();

        [DllImport("kernel32", SetLastError = true)]
        static extern bool AttachConsole(int dwProcessId);

        [DllImport("user32.dll")]
        static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll", SetLastError = true)]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

        public void consoleThreadStart()
        {
            //TODO: better handling of command args, (handle help (--help /?) etc.

            //Get a pointer to the forground window.  The idea here is that
            //IF the user is starting our application from an existing console
            //shell, that shell will be the uppermost window.  We'll get it
            //and attach to it
            IntPtr ptr = GetForegroundWindow();

            int u;

            GetWindowThreadProcessId(ptr, out u);

            Process process = Process.GetProcessById(u);

                AllocConsole();

            Console.ForegroundColor = ConsoleColor.Yellow;
            startCommands();
            while (true)
                readCommand();
        }
        public void readCommand()
        {

            command = Console.ReadLine();
            foreach (Command comm in commands)
            {
                if (command == comm.command)
                {
                    Console.WriteLine("Command exists.");
                    executeCommand();
                    commandExists = true;
                }
            }
            if (commandExists)
            {
                commandExists = false;
            }
            else
            {
                Console.WriteLine("Command doesn't exist.  Try again.  Remember, it's case sensitive.");
            }
        }
        public void startCommands()
        {
            commands.Add(new Command("Exit"));
            commands.Add(new Command("Move Camera"));
            commands.Add(new Command("Move"));
        }
        public void executeCommand()
        {
            if (command == "Exit")
            {
                Environment.Exit(0);
            }
            if (command == "Move")
            {
                Console.WriteLine("Move what?  There are sub commands:  ");
                Console.WriteLine("1.  Camera  ex.  Move Camera 1 1 1"); // To do:  Automate this so we don't have to hard-code each
                // sub command.
            }
            if (command == "Move Camera")
            {
                // If I can figure this out...
            }
        }
#endif
        #endregion

        public bool minimized;
        public bool readingInput;
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        List<CModel> models = new List<CModel>();
        Camera camera;
#if DEBUG
        System.Threading.Thread consoleThread;
#endif

    #if XBOX_GAME
        //Joystick stuff here.
    #else
        System.Drawing.Rectangle screen;
        
        MouseState lastMouseState;
    #endif

        // Event Handlers
        private void ActivatedEventHandler(object sender, EventArgs e)
        {
            minimized = false;
        }
        private void DeactivatedEventHandler(object sender,EventArgs e)
        {
            minimized = true;
        }


        public Game1()
        {
                
            graphics = new GraphicsDeviceManager(this);
            minimized = false;
            Content.RootDirectory = "Content";
#if XBOX_GAME
            //Screen resolution is probably constant on XBox 360.  Add logic for that here.
#else

            screen = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
            graphics.PreferredBackBufferWidth = screen.Width;
            graphics.PreferredBackBufferHeight = screen.Height;
            // graphics.ToggleFullScreen();
#endif

            consoleThread = new System.Threading.Thread(consoleThreadStart);
            consoleThread.Start();
        }


        #region Load Content
        // Called when the game should load its content
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            loadModels();
            loadEffects();
            camera = new FreeCamera(new Vector3(1000, 1500, -2000), MathHelper.ToRadians(153),
                MathHelper.ToRadians(5), GraphicsDevice);

            Mouse.SetPosition(graphics.PreferredBackBufferWidth / 2, graphics.PreferredBackBufferHeight / 2);
            lastMouseState = Mouse.GetState();
        }

        protected void loadModels()
        {
            models.Add(new CModel(Content.Load<Model>("Ground"), new Vector3(0, 0, 0), Vector3.Zero, new Vector3(1f), GraphicsDevice));
            models.Add(new CModel(Content.Load<Model>("Models\\TestModel"), new Vector3(0, 60, 0), Vector3.Zero, new Vector3(10f), GraphicsDevice));
            models.Add(new CModel(Content.Load<Model>("ship"), new Vector3(0, 350, 5000), Vector3.Zero, new Vector3(1f), GraphicsDevice));
        }

        protected void loadEffects()
        {
            // Load them
            Effect simpleEffect = Content.Load<Effect>("Effects\\SimpleEffect");
            Effect lightingEffect = Content.Load<Effect>("Effects\\LightingEffect");
            Effect pointLightEffect = Content.Load<Effect>("Effects\\PointLIghtEffect");

            // Apply them.
            models[0].SetModelEffect(pointLightEffect, true);
            models[1].SetModelEffect(lightingEffect, true);
            models[2].SetModelEffect(lightingEffect, true);

            // Materials
            LightingMaterial lightingMat = new LightingMaterial();
            PointLightMaterial pointLightingMat = new PointLightMaterial();


            // Material Parameters / fields
            lightingMat.AmbientColor = Color.Green.ToVector3() * .2f; // Multiplier = Color intensity
            lightingMat.LightColor = Color.Goldenrod.ToVector3() * .8f;

            pointLightingMat.LightPosition = new Vector3(0, 1500, 1500);
            pointLightingMat.LightAttenuation = 3000;

            // Apply materials
            models[0].Material = pointLightingMat;
            models[1].Material = lightingMat;
            models[2].Material = lightingMat;

        }
        #endregion
        #region Update and Draw
        // Called when the game should update itself
        protected override void Update(GameTime gameTime)
        {
            this.Deactivated += new System.EventHandler<EventArgs>(DeactivatedEventHandler);
            this.Activated += new System.EventHandler<EventArgs>(ActivatedEventHandler);
            // Need to detect if minimized here
            if (!minimized)
            {
                // Escape sequence
                KeyboardState keyState = Keyboard.GetState();
                if (keyState.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape))
                {
                    UnloadContent();
                    Environment.Exit(0);
                }

                updateCamera(gameTime);
                base.Update(gameTime);
            }
        }


        void updateCamera(GameTime gameTime)
        {
            MouseState mouseState = Mouse.GetState();
            KeyboardState keyState = Keyboard.GetState();
            Mouse.SetPosition(640, 400);

            float deltaX = 640 - (float)mouseState.X;
            float deltaY = 400 - (float)mouseState.Y;

            ((FreeCamera)camera).Rotate(deltaX * .01f, deltaY * .01f);

            Vector3 translation = Vector3.Zero;

            if (keyState.IsKeyDown(Keys.W))
            {
                translation += Vector3.Forward * 2;
            }
            if (keyState.IsKeyDown(Keys.S))
            {
                translation += Vector3.Backward;
            }
            if (keyState.IsKeyDown(Keys.A))
            {
                translation += Vector3.Left;
            }
            if (keyState.IsKeyDown(Keys.D))
            {
                translation += Vector3.Right;
            }

            translation *= 3 * (float)gameTime.ElapsedGameTime.TotalMilliseconds;

            ((FreeCamera)camera).Move(translation);

            camera.Update();

            lastMouseState = mouseState;
        }


    // Called when the game should draw itself
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.DarkBlue);
            foreach (CModel model in models)
                    model.Draw(camera.View, camera.Projection,
                    ((FreeCamera)camera).Position);

            base.Draw(gameTime);
        }
        #endregion
    }
}